package com.ycjy.szteacher.realm;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ycjy.szteacher.entity.Teacher;
import com.ycjy.szteacher.mapper.TeacherMapper;
import com.ycjy.szteacher.service.TeacherService;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * @Classname MyShiroRealm
 * @Description TODO
 * @Date 2020/3/22 23:09
 * @Created by x1c
 */

public class MyShiroRealm extends AuthorizingRealm {
    @Resource
    private TeacherMapper teacherMapper;

    @Override
    public void setName(String name) {
        // TODO Auto-generated method stub
        super.setName("myShiroRealm");
    }

    /*主要是用来进行身份认证的，也就是说验证用户输入的账号和密码是否正确。
     * doGetAuthorizationInfo() 方法：为当前登录成功的用户授予权限和分配角色
     * */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 获取用户名
        String username = (String) principalCollection.getPrimaryPrincipal();
        Set<String> roles = new HashSet<String>();
        if (username.equals("admin")) {
            roles.add("admin");
        } else {
            roles.add("教师");
        }
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // 给该用户设置角色，角色信息存在 t_role 表中取
        authorizationInfo.setRoles(roles);
        return authorizationInfo;
    }

    /**
     * @param loginName
     * @功能描述： 单用户登录, 清除当前用户以前登录时保存的session会话
     */
    public void singleUseLogin1(String loginName) {
        // 1.获取当前用户sessionId
        String currentUserSessionId = SecurityUtils.getSubject().getSession().getId().toString();

        // 2.获取shiro的sessionManager
        DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
        DefaultWebSessionManager sessionManager = (DefaultWebSessionManager) securityManager.getSessionManager();
        System.out.println(111);
        // 3.获取所有已登录用户的session列表
        Collection<Session> sessions = ((DefaultSessionManager) ((DefaultSecurityManager) SecurityUtils
                .getSecurityManager()).getSessionManager()).getSessionDAO()
                .getActiveSessions();

        if (sessions.size() > 1) {
            System.out.println("仅允许单用户登录,开始清理遗留用户信息~");
            Teacher user = null;
            for (Session onlineSession : sessions) {
                // 4. 获取已登录用户的session的key值
                SimplePrincipalCollection simplePrincipalCollection = (SimplePrincipalCollection) onlineSession.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
                if (null == simplePrincipalCollection) {
                    sessionManager.getSessionDAO().delete(onlineSession);
                    continue;
                }
                // 5. 获取new SimpleAuthenticationInfo(user, pwd, this.getName())中放进去的第一个参数
                user = (Teacher) simplePrincipalCollection.getPrimaryPrincipal();
                // 6. 清除当前用户以前登录时保存的session会话
                if (loginName.equals(user.getTeacherName()) && !onlineSession.getId().equals(currentUserSessionId)) {
                    sessionManager.getSessionDAO().delete(onlineSession);
                    System.out.println("清理用户[" + loginName + "],SessionId为[" + onlineSession.getId() + "]的Session信息!");
                }
            }
        } else {
            System.out.println("无可清理用户信息~");
        }
    }

    /**
     * @param loginName
     * @功能描述： 单用户登录, 清除当前用户以前登录时保存的session会话
     */
    public void singleUseLogin2(HttpServletRequest request, String loginName) {
        // 1.获取当前用户sessionId
        String currentUserSessionId = request.getSession().getId();

        // 2.获取shiro的sessionManager
        DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
        DefaultWebSessionManager sessionManager = (DefaultWebSessionManager) securityManager.getSessionManager();

        // 3.获取所有已登录用户的session列表
        Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions();

        // 处理方法一:UserRalm中传入的是userName使用此方法
        String onlineSessionKey = "";
        for (Session onlineSession : sessions) {
            // 4.获取已登录用户的session的key值
            onlineSessionKey = String.valueOf(onlineSession.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY));
            // 5.清除当前用户以前登录时保存的session会话
            System.out.println(onlineSession.getId() + "------" + onlineSessionKey);

            if (onlineSessionKey.equals("null")) {
                sessionManager.getSessionDAO().delete(onlineSession);
            } else if (loginName.equals(onlineSessionKey) && !onlineSession.getId().equals(currentUserSessionId)) {
                sessionManager.getSessionDAO().delete(onlineSession);
            }
        }
    }

    /*
     *
     * doGetAuthenticationInfo() 方法：用来验证当前登录的用户，获取认证信息。
     * */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 根据 Token 获取用户名，如果您不知道该 Token 怎么来的，先可以不管，下文会解释
        String username = (String) authenticationToken.getPrincipal();
        QueryWrapper<Teacher> wrapper = new QueryWrapper<>();
        wrapper.eq("teacherName", username);
        // 根据用户名从数据库中查询该用户
        Teacher teacher = teacherMapper.selectOne(wrapper);
        String pwd = new String((char[]) authenticationToken.getCredentials());
        if (teacher != null) {
            // 把当前用户存到 Session 中
            SecurityUtils.getSubject().getSession().setAttribute("user", teacher);
            // 传入用户名和密码进行身份认证，并返回认证信息
            AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(teacher.getTeacherName(), pwd, "myRealm");
            return authcInfo;
        } else {
            return null;
        }

    }
}
